unit heContnrs_VectorSet_test;

{$mode objfpc}{$H+}

interface

uses
  Classes,
  fpcunit,
  heContnrs,
  heContnrs_test;

type

  TVectorSetInt = type Integer;

  { TTestVectorSetInt }

  _TTestVectorSetInt = specialize TheVectorSet<TVectorSetInt>;
  TTestVectorSetInt = class(_TTestVectorSetInt)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  TVectorSetStr = type String;

  { TTestVectorSetStr }

  _TTestVectorSetStr = specialize TheVectorSet<TVectorSetStr>;
  TTestVectorSetStr = class(_TTestVectorSetStr)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestCmpVectorSetInt }

  _TTestCmpVectorSetInt = specialize TheCmpVectorSet<Integer>;
  TTestCmpVectorSetInt = class(_TTestCmpVectorSetInt)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: Integer): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestCmpVectorSetStr }

  _TTestCmpVectorSetStr = specialize TheCmpVectorSet<String>;
  TTestCmpVectorSetStr = class(_TTestCmpVectorSetStr)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: String): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestCmpVectorSetInterface }

  _TTestCmpVectorSetInterface = specialize TheCmpVectorSet<IInterface>;
  TTestCmpVectorSetInterface = class(_TTestCmpVectorSetInterface)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: IInterface): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestObjectVectorSet }

  _TTestObjectVectorSet = specialize TheObjectVectorSet<TTracedObject>;
  TTestObjectVectorSet = class(_TTestObjectVectorSet)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: TTracedObject): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TheVectorSetTest }

  generic TheVectorSetTest<TVector, TItem> = class(TTestCase)
  private
    Vector: TVector;
  protected
    function Item(const N: Integer): TItem; virtual; // abstract;
    function Value(const It: TItem): Integer; virtual; // abstract;
    procedure Done(var It: TItem); virtual;
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestCreate;
    procedure TestInclude;
    procedure TestExclude;
  //  procedure TestGetEnumerator;
  //  procedure TestReversed;
    procedure TestClear;
    procedure TestPack;
    procedure TestFirst;
    procedure TestLast;
    procedure TestMembership;
  end;

  { TheIntVectorSetTest }

  _TheIntVectorSetTest = specialize TheVectorSetTest<TTestVectorSetInt, Integer>;
  TheIntVectorSetTest = class(_TheIntVectorSetTest)
  protected
    function Item(const N: Integer): Integer; override;
    function Value(const It: Integer): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheStrVectorSetTest }

  _TheStrVectorSetTest = specialize TheVectorSetTest<TTestVectorSetStr, String>;
  TheStrVectorSetTest = class(_TheStrVectorSetTest)
  protected
    function Item(const N: Integer): String; override;
    function Value(const It: String): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheIntCmpVectorSetTest }

  _TheIntCmpVectorSetTest = specialize TheVectorSetTest<TTestCmpVectorSetInt, Integer>;
  TheIntCmpVectorSetTest = class(_TheIntCmpVectorSetTest)
  protected
    function Item(const N: Integer): Integer; override;
    function Value(const It: Integer): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheStrCmpVectorSetTest }

  _TheStrCmpVectorSetTest = specialize TheVectorSetTest<TTestCmpVectorSetStr, String>;
  TheStrCmpVectorSetTest = class(_TheStrCmpVectorSetTest)
  protected
    function Item(const N: Integer): String; override;
    function Value(const It: String): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheInterfaceCmpVectorSetTest }

  _TheInterfaceCmpVectorSetTest = specialize TheVectorSetTest<TTestCmpVectorSetInterface, IInterface>;
  TheInterfaceCmpVectorSetTest = class(_TheInterfaceCmpVectorSetTest)
  protected
    function Item(const N: Integer): IInterface; override;
    function Value(const It: IInterface): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheObjectVectorSetTest }

  _TheObjectVectorSetTest = specialize TheVectorSetTest<TTestObjectVectorSet, TTracedObject>;
  TheObjectVectorSetTest = class(_TheObjectVectorSetTest)
  protected
    function Item(const N: Integer): TTracedObject; override;
    function Value(const It: TTracedObject): Integer; override;
    procedure Done(var It: TTracedObject); override;
  published
    procedure TestKill;
    procedure TestWipe;
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

implementation

uses
  SysUtils,
  testregistry;

function I2S(const N: Integer): String;
begin
  if N < 0 then
    Result := Format('N%.8x', [N])
  else
    Result := Format('P%.8x', [N]);
end;

function S2I(const S: String): Integer;
begin
  Result := StrToInt('$' + Copy(S, 2, Length(S)));
end;

{ TTestCmpVectorSetInt }

constructor TTestCmpVectorSetInt.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestCmpVectorSetInt.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestCmpVectorSetInt.Compare(const A, B: Integer): Integer;
begin
  Result := A - B;
end;

{ TTestVectorSetInt }

constructor TTestVectorSetInt.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestVectorSetInt.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

{ TTestVectorSetStr }

constructor TTestVectorSetStr.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestVectorSetStr.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

{ TTestCmpVectorSetStr }

constructor TTestCmpVectorSetStr.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestCmpVectorSetStr.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestCmpVectorSetStr.Compare(const A, B: String): Integer;
begin
  Result := CompareStr(A, B);
end;

{ TTestCmpVectorSetInterface }

constructor TTestCmpVectorSetInterface.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestCmpVectorSetInterface.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestCmpVectorSetInterface.Compare(const A, B: IInterface): Integer;
begin
  if (A = nil) then
    if B = nil then
      Exit(0)
    else
      Exit(1)
  else if B = nil then
    if A = nil then
      Exit(0)
    else
      Exit(-1);
  Result := (A as TInterfacedTracedObject).ID - (B as TInterfacedTracedObject).ID;
end;

{ TTestObjectVectorSet }

constructor TTestObjectVectorSet.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create(True);
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestObjectVectorSet.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestObjectVectorSet.Compare(const A, B: TTracedObject): Integer;
begin
  if A = B then
    Exit(0);
  if A = nil then
    Exit(-1)
  else if B = nil then
    Exit(1);
  Result := A.ID - B.ID;
end;

{ TheIntVectorSetTest }

function TheIntVectorSetTest.Item(const N: Integer): Integer;
begin
  Result := N;
end;

function TheIntVectorSetTest.Value(const It: Integer): Integer;
begin
  Result := It;
end;

procedure TheIntVectorSetTest.TestGetEnumerator;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) < Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

procedure TheIntVectorSetTest.TestReversed;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector.Reversed do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector.Reversed do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) > Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

{ TheStrVectorSetTest }

function TheStrVectorSetTest.Item(const N: Integer): String;
begin
  Result := I2S(N);
end;

function TheStrVectorSetTest.Value(const It: String): Integer;
begin
  Result := S2I(It);
end;

procedure TheStrVectorSetTest.TestGetEnumerator;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) < Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

procedure TheStrVectorSetTest.TestReversed;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector.Reversed do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector.Reversed do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) > Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

{ TheIntCmpVectorSetTest }

function TheIntCmpVectorSetTest.Item(const N: Integer): Integer;
begin
  Result := N;
end;

function TheIntCmpVectorSetTest.Value(const It: Integer): Integer;
begin
  Result := It;
end;

procedure TheIntCmpVectorSetTest.TestGetEnumerator;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) < Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

procedure TheIntCmpVectorSetTest.TestReversed;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector.Reversed do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector.Reversed do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) > Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

{ TheStrCmpVectorSetTest }

function TheStrCmpVectorSetTest.Item(const N: Integer): String;
begin
  Result := I2S(N);
end;

function TheStrCmpVectorSetTest.Value(const It: String): Integer;
begin
  Result := S2I(It);
end;

procedure TheStrCmpVectorSetTest.TestGetEnumerator;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) < Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

procedure TheStrCmpVectorSetTest.TestReversed;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector.Reversed do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector.Reversed do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) > Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

{ TheInterfaceCmpVectorSetTest }

function TheInterfaceCmpVectorSetTest.Item(const N: Integer): IInterface;
begin
  Result := TInterfacedTracedObject.Create(nil, N);
end;

function TheInterfaceCmpVectorSetTest.Value(const It: IInterface): Integer;
begin
  Result := (It as TInterfacedTracedObject).ID;
end;

procedure TheInterfaceCmpVectorSetTest.TestGetEnumerator;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) < Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

procedure TheInterfaceCmpVectorSetTest.TestReversed;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector.Reversed do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector.Reversed do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) > Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

{ TheObjectVectorSetTest }

function TheObjectVectorSetTest.Item(const N: Integer): TTracedObject;
begin
  if N = -1 then
    Exit(nil);
  Result := TTracedObject.Create(nil, N);
end;

function TheObjectVectorSetTest.Value(const It: TTracedObject): Integer;
begin
  if It = nil then
    Exit(-1);
  Result := It.ID;
end;

procedure TheObjectVectorSetTest.Done(var It: TTracedObject);
begin
  FreeAndNil(It);
end;

procedure TheObjectVectorSetTest.TestKill;
var
  V: TTestObjectVectorSet;
  Tracer: TBits;
  Obj: TTracedObject;
begin
  Tracer := TBits.Create;
  try
    V := TTestObjectVectorSet.Create(Tracer, 0);
    try
      Obj := TTracedObject.Create(Tracer, 1);
      try
        AssertTrue('V alive', Tracer[0]);
        AssertTrue('a) Obj alive', Tracer[1]);
        V.Kill;
        V := nil;
        AssertFalse('V dead', Tracer[0]);
        AssertTrue('b) Obj alive', Tracer[1]);
      finally
        Obj.Free;
      end;
    finally
      V.Free;
    end;
  finally
    Tracer.Free;
  end;
end;

procedure TheObjectVectorSetTest.TestWipe;
var
  V: TTestObjectVectorSet;
  Tracer: TBits;
  Obj: TTracedObject;
begin
  Tracer := TBits.Create;
  try
    V := TTestObjectVectorSet.Create(nil, 0);
    try
      Obj := TTracedObject.Create(Tracer, 1);
      try
        AssertTrue('a) Obj alive', Tracer[1]);
        V.Wipe;
        AssertEquals('.Count', 0, V.Count);
        AssertTrue('b) Obj alive', Tracer[1]);
      finally
        Obj.Free;
      end;
    finally
      V.Free;
    end;
  finally
    Tracer.Free;
  end;
end;

procedure TheObjectVectorSetTest.TestGetEnumerator;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) < Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

procedure TheObjectVectorSetTest.TestReversed;
const N = 100;
var
  I, J: Integer;
  L, V: TItem;
begin
  J := 0;
  for V in Vector.Reversed do
    Inc(J);
  AssertEquals('J0', 0, J);
  for I := 0 to N - 1 do begin
    AssertEquals('.Count', I, Vector.Count);
    AssertFalse('.Include', Vector.Include(Item(I)));
    J := 0;
    L := Item(-1);
    for V in Vector.Reversed do begin
      AssertTrue('V', Value(V) in [0..I]);
      if Value(L) >= 0 then
        AssertTrue('Ordering', Value(L) > Value(V));
      L := V;
      Inc(J);
    end;
    AssertEquals('J', I + 1, J);
  end;
end;

{ TheVectorSetTest }

function TheVectorSetTest.Item(const N: Integer): TItem;
begin
  Assert(N = N); // hint off
  Initialize(Result); // hint off
  raise EAbstractError.Create(Format('%s.Item', [ClassName]));
end;

function TheVectorSetTest.Value(const It: TItem): Integer;
begin
  Assert(@It = @It); // hint off
  Initialize(Result); // hint off
  raise EAbstractError.Create(Format('%s.Value', [ClassName]));
end;

procedure TheVectorSetTest.Done(var It: TItem);
begin
  Assert(@It = @It); // hint off
end;

procedure TheVectorSetTest.SetUp;
begin
  Vector := TVector.Create(nil, 0);
end;

procedure TheVectorSetTest.TearDown;
begin
  FreeAndNil(Vector);
end;

procedure TheVectorSetTest.TestCreate;
begin
  AssertEquals('Initial .Count', 0, Vector.Count);
end;

procedure TheVectorSetTest.TestInclude;
var Item0, Item10: TItem;
begin
  AssertEquals('a1) .Count', 0, Vector.Count);
  AssertFalse('b1) .Include', Vector.Include(Item(0)));
  AssertEquals('c1) .Count', 1, Vector.Count);
  Item0 := Item(0);
  try
    AssertTrue('d1) .Include', Vector.Include(Item0));
    AssertEquals('e1) .Count', 1, Vector.Count);
  finally
    Done(Item0);
  end;
  TearDown;

  SetUp;
  AssertEquals('a2) .Count', 0, Vector.Count);
  AssertFalse('b2) .Include', Vector.Include(Item(0)));
  AssertEquals('c2) .Count', 1, Vector.Count);
  AssertFalse('d2) .Include', Vector.Include(Item(10)));
  AssertEquals('e2) .Count', 2, Vector.Count);
  Item0 := Item(0);
  Item10 := Item(10);
  try
    AssertTrue('f2) .Include', Vector.Include(Item0));
    AssertTrue('g2) .Include', Vector.Include(Item10));
  finally
    Done(Item0);
    Done(Item10);
  end;
  AssertEquals('h2) .Count', 2, Vector.Count);
  TearDown;

  SetUp;
  AssertEquals('a3) .Count', 0, Vector.Count);
  AssertFalse('b3) .Include', Vector.Include(Item(10)));
  AssertEquals('c3) .Count', 1, Vector.Count);
  AssertFalse('d3) .Include', Vector.Include(Item(0)));
  AssertEquals('e3( .Count', 2, Vector.Count);
  Item0 := Item(0);
  Item10 := Item(10);
  try
    AssertTrue('f3) .Include', Vector.Include(Item10));
    AssertTrue('g3) .Include', Vector.Include(Item0));
  finally
    Done(Item0);
    Done(Item10);
  end;
  AssertEquals('h3) .Count', 2, Vector.Count);
end;

procedure TheVectorSetTest.TestExclude;
var Item0_, Item10_, Item0, Item10: TItem;
begin
  Item0_ := Item(0);
  Item0 := Item(0);
  try
    AssertFalse('a1) .Exclude', Vector.Exclude(Item0));
    AssertFalse('b1) .Include', Vector.Include(Item0_));
    AssertTrue('c1) .Exclude', Vector.Exclude(Item0));
    AssertFalse('d1) .Exclude', Vector.Exclude(Item0));
    AssertEquals('e1', 0, Vector.Count);
  finally
    Done(Item0_);
    Done(Item0);
  end;
  TearDown;

  SetUp;
  Item0_ := Item(0);
  Item0 := Item(0);
  Item10_ := Item(10);
  Item10 := Item(10);
  try
    AssertFalse('a2) .Exclude', Vector.Exclude(Item0));
    AssertFalse('b2) .Exclude', Vector.Exclude(Item10));
    AssertFalse('c2) .Include', Vector.Include(Item0));
    AssertTrue('d2) .Exclude', Vector.Exclude(Item0_));
    AssertFalse('e2) .Exclude', Vector.Exclude(Item0_));
    AssertFalse('f2) .Exclude', Vector.Exclude(Item10_));
    AssertEquals('g2', 0, Vector.Count);
  finally
    Done(Item0);
    Done(Item0_);
    Done(Item10);
    Done(Item10_);
  end;
  TearDown;

  SetUp;
  Item0_ := Item(0);
  Item0 := Item(0);
  Item10_ := Item(10);
  Item10 := Item(10);
  try
    AssertFalse('a3) .Exclude', Vector.Exclude(Item0));
    AssertFalse('b3) .Exclude', Vector.Exclude(Item10));
    AssertFalse('c3) .Include', Vector.Include(Item0));
    AssertFalse('d3) .Include', Vector.Include(Item10));
    AssertTrue('e3) .Include', Vector.Include(Item0_));
    AssertTrue('f3) .Exclude', Vector.Exclude(Item0_));
    AssertTrue('g3) .Exclude', Vector.Exclude(Item10_));
    AssertFalse('h3) .Exclude', Vector.Exclude(Item0_));
    AssertFalse('i3) .Exclude', Vector.Exclude(Item10_));
    AssertEquals('j3', 0, Vector.Count);
  finally
    Done(Item0);
    Done(Item0_);
    Done(Item10);
    Done(Item10_);
  end;
end;

procedure TheVectorSetTest.TestClear;
const N = 10;
var I: Integer;
begin
  for I := 0 to N - 1 do
    Vector.Include(Item(I));
  Vector.Clear;
  AssertEquals('.Count', 0, Vector.Count);
end;

procedure TheVectorSetTest.TestPack;
const N = 11;
var I: Integer;
begin
  for I := 0 to N - 1 do
    Vector.Include(Item(I));
  Vector.Capacity := 2 * N;
  AssertEquals('a) .Capacity', 2 * N, Vector.Capacity);
  Vector.Pack;
  AssertEquals('b) .Capacity', Vector.Count, Vector.Capacity);
end;

procedure TheVectorSetTest.TestFirst;
var ItemA, ItemB: TItem;
begin
  ItemA := Item(100);
  Vector.Include(ItemA);
  AssertEquals('a1) .First', Value(ItemA), Value(Vector.First));
  ItemB := Item(200);
  Vector.Include(ItemB);
  AssertEquals('a2) .First', Value(ItemA), Value(Vector.First));
  Assert(@ItemB = @ItemB); // hint off
end;

procedure TheVectorSetTest.TestLast;
var ItemA, ItemB: TItem;
begin
  ItemA := Item(100);
  Vector.Include(ItemA);
  AssertEquals('a1) .Last', Value(ItemA), Value(Vector.Last));
  ItemB := Item(200);
  Vector.Include(ItemB);
  AssertEquals('a2) .Last', Value(ItemB), Value(Vector.Last));
end;

procedure TheVectorSetTest.TestMembership;
var
  I, Bit: Byte;
  A: array [0..4] of TItem;
begin
  for I := Low(A) to High(A) do
    A[I] := Item(I);
  for I := 0 to (2 shl High(A)) - 1 do begin
    for Bit := Low(A) to High(A) do
      Vector[A[Bit]] := (I and (1 shl Bit)) <> 0;
    for Bit := Low(A) to High(A) do
      AssertEquals((I and (1 shl Bit)) <> 0, Vector[A[Bit]]);
  end;
  Assert(@A = @A); // hint off
end;

initialization
  RegisterTests([
    TheIntVectorSetTest,
    TheStrVectorSetTest,
    TheIntCmpVectorSetTest,
    TheStrCmpVectorSetTest,
    TheInterfaceCmpVectorSetTest,
    TheObjectVectorSetTest
  ]);

end.

